package com.wangjiang.mario.admin.system.domain.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wangjiang.mario.admin.common.base.BaseServiceImpl;
import com.wangjiang.mario.admin.common.util.CommonUtils;
import com.wangjiang.mario.admin.common.util.DateUtil;
import com.wangjiang.mario.admin.common.util.StringUtils;
import com.wangjiang.mario.admin.system.domain.components.CacheComponent;
import com.wangjiang.mario.admin.system.domain.entity.WxMicroappEntity;
import com.wangjiang.mario.admin.system.domain.mapper.WxMicroappMapper;
import com.wangjiang.mario.admin.system.domain.service.WxMicroappService;
import com.wangjiang.mario.admin.system.domain.util.WechatGetUserInfoUtil;
import com.wangjiang.mario.admin.system.domain.util.WxAppUtil;
import com.wangjiang.mario.admin.system.object.wxapp.WxAccessTokenCacheData;
import com.wangjiang.mario.admin.system.object.wxapp.WxAppLoginRet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class WxMicroappServiceImpl extends BaseServiceImpl<WxMicroappMapper, WxMicroappEntity>
        implements WxMicroappService {

    private static final Logger logger = LoggerFactory.getLogger(WxMicroappServiceImpl.class);

    private static final String WXAPP_ACCESS_TOKEN = "WXAPP_ACCESS_TOKEN";

    @Autowired
    private CacheComponent cacheComponent;

    /**
     * 微信小程序登录
     *
     * @param appid
     * @param code
     * @return
     */
    @Override
    public WxAppLoginRet wxAppLogin(String appid, String code) {
        WxMicroappEntity wxMicroappEntity = getByAppid(appid);
        String url = WxAppUtil.getCode2SessionURLString(wxMicroappEntity.getAppId(), wxMicroappEntity.getAppSecret(), code);
        // 开始请求
        String retString = HttpUtil.get(url);
        JSONObject jsonObject = (JSONObject) JSONObject.parse(retString);
        WxAppLoginRet ret = new WxAppLoginRet();
        BeanUtils.copyProperties(jsonObject, ret);
        // session_key 不向前台返回
        ret.setSession_key(null);
        return ret;
    }

    @Override
    public WxMicroappEntity getByAppid(String appid) {
        QueryWrapper defaultWrapper = getDefaultWrapper();
        defaultWrapper.eq("app_id", appid);
        return getOne(defaultWrapper);
    }

    /**
     * 获取access_token, 并存储到redis中,
     *
     * @param appid
     * @return
     */
    @Override
    public String getAccessToken(String appid) {
        return getAccessToken(appid, null);
    }

    /**
     * 获取access_token, 并存储到redis中,
     *
     * @param appid
     * @return
     */
    @Override
    public String getAccessToken(String appid, WxMicroappEntity app) {
        // 先从redis获取, 查看剩余时间，剩余时间低于5分钟，则从服务器重新获取，然后使用新的access_token， 否则直接返回旧的token
        String cacheTokenKey = StringUtils.format("APPID_{}", appid);

        if (cacheComponent.hasKey(WXAPP_ACCESS_TOKEN, cacheTokenKey)) {
            String cacheDataString = (String) cacheComponent.get(WXAPP_ACCESS_TOKEN, cacheTokenKey);
            WxAccessTokenCacheData cacheData  = JSONObject.parseObject(cacheDataString, WxAccessTokenCacheData.class);
            Date now = DateUtil.getNowDate();
            Long leftDuration = cacheData.getExpire_in() - (now.getTime() - cacheData.getCacheTime().getTime()) / 1000; //剩余缓存时间 多少秒
            logger.info("access_token 缓存时间还剩{}秒", leftDuration);
            // 小于5分钟，则重新获取
            if (leftDuration >= (5 * 60)) {
                return cacheData.getAccess_token();
            }
        }

        if(CommonUtils.isNull(app)) {
            app = getByAppid(appid);
        }
        String retString = WxAppUtil.getAccessToken(appid, app.getAppSecret());
        JSONObject accessTokenObject = (JSONObject) JSONObject.parse(retString);
        String accessToken = cacheAccessToken(accessTokenObject, cacheTokenKey);

        return accessToken;
    }

    /**
     * 获取小程序用户信息
     *
     * @param appid
     * @param code
     * @param encryptedData
     * @param iv
     * @return
     */
    @Override
    public JSONObject getUserInfo(String appid, String code, String encryptedData, String iv) {
        WxMicroappEntity wxMicroappEntity = getByAppid(appid);

        String sessionKey = WxAppUtil.getSessionKey(appid, wxMicroappEntity.getAppSecret(), code);

        if (CommonUtils.isNull(sessionKey)) {
            throw new RuntimeException("session_key 获取失败");
        }

        JSONObject jsonObject = WechatGetUserInfoUtil.getUserInfo(encryptedData, sessionKey, iv);

        return jsonObject;
    }

    private String cacheAccessToken(JSONObject accessToken, String cacheTokenKey) {

        String tokenString = (String) accessToken.get("access_token");
        Integer expiresIn = (Integer) accessToken.get("expires_in");
        // 新建缓存对象
        WxAccessTokenCacheData cacheData = new WxAccessTokenCacheData();
        cacheData.setAccess_token(tokenString);
        cacheData.setExpire_in(expiresIn);
        cacheData.setCacheTime(DateUtil.getNowDate());

        //格式化成jsonString
        String cacheDataString = JSONObject.toJSONString(cacheData);

        // 存入token字符串到redis
        cacheComponent.put(WXAPP_ACCESS_TOKEN, cacheTokenKey, cacheDataString, expiresIn);

        return tokenString;
    }

}
